import weakref
import pattern.circuit


class CircuitOperability(object):
    """
    Represents the aspect in which a circuit operates the logical controls
    contained in it.
    """

    def emit(self, e4shape, cb, **kwargs):
        container = self.get_container(e4shape)
        if container is not None:
            self.call(e4shape.anchor().origin().shape(), "emit",
                      fallback=lambda *_a,**_kw: self.call(e4shape, cb, **kwargs),
                      for_shape=e4shape, slot=cb, kwargs=kwargs)
        else:
            self.call(e4shape, cb, **kwargs)
        
    def call(self, e4shape, cb, fallback=None, **kwargs):
        import codebase
        component = codebase.getComponent(e4shape)
        if hasattr(component, cb):
            e = pattern.circuit.Event()
            e._weak_window = weakref.ref(self)
            e._weak_shape = weakref.ref(e4shape)
            for key, value in kwargs.items():
                setattr(e, key, value)
            return getattr(component, cb)(e)
        elif fallback is not None:
            fallback(e4shape, cb, **kwargs)

    def get_container(self, shape):
        try:
            return shape.anchor().origin().shape()
        except AttributeError:
            return None

    def restart(self, shape):
        try:
            self.emit(shape, "shutdown")
        finally:
            import codebase
            codebase.reloadComponent(shape)
            self.emit(shape, "realize")
                
    def notify(self, category, notification, clear=False):
        pass

    def denotify(self, category):
        pass

    def manipulate(self, shape, manip):
        manip(shape)

    def populate(self, shapes):
        import codebase
        for shape in shapes:
            try:
                self.restart(shape)
            except:
                import traceback
                traceback.print_exc()



class CircuitGeometry(object):
    """
    Represents the aspect in which the circuit is a geometric model of
    blocks and connectors.
    """

    def isOutlet(self, connectionpoint, outlet):
        if hasattr(connectionpoint, 'attachment'):
           if repr(connectionpoint.attachment) == outlet:
               return True
        if hasattr(connectionpoint, 'tag'):
            if connectionpoint.tag == outlet:
                return True
        for connection in connectionpoint.xref:
            if hasattr(connection(), 'caption'):
                if connection().caption == outlet:
                    return True
        return False

    def getCaption(self, point):
        for connection in point.xref:
            if hasattr(connection(), 'caption'):
                return connection().caption

    def acquireOutlet(self, event, outlet):
        for connectionpoint in event.shape.xref:
            if self.isOutlet(connectionpoint(), outlet):
                return connectionpoint()

    def acquireConnectionsAt(self, event, connectionpoint):
        for connection in connectionpoint().xref:
            if hasattr(connection(), 'points'):
                yield pattern.circuit.Bridge(event.window, connectionpoint,
                                             connection, event.trail,
                                             event.frame)

    def acquireAnchoredAt(self, event, connectionpoint):
        for anchor in connectionpoint().xref:
            if isinstance(anchor(), event.window.Point):
                for anchored in anchor().xref:
                    yield pattern.circuit.SubBridge(event.window,
                                           connectionpoint, anchored,
                                           event.trail, event.frame)

    def acquireInterfaces(self, event, outlet):
        for connectionpoint in event.shape.xref:
            if self.isOutlet(connectionpoint(), outlet):
                return list(self.acquireConnectionsAt(event, connectionpoint))
        return []

    def acquireInterface(self, event, outlet):
        return (self.acquireInterfaces(event, outlet) + [None])[0]

    def acquireSubcomponents(self, event):
        interest = set()
        for connectionpoint in event.shape.xref:
            interest.update(self.acquireAnchoredAt(event, connectionpoint))
        return interest



class Circuit(CircuitOperability, CircuitGeometry):
    pass
